// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// y [author] rhyme_lph
// G [email]  rhymelph@gmail.com
// U [github] https://github.com/rhymelph

import 'dart:async';

import 'package:base_plugin/base_plugin.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/common/config.dart';
import 'package:finance_app/src/entities/contribution_entity.dart';
import 'package:finance_app/src/entities/employee_contact_entity.dart';
import 'package:finance_app/src/entities/employment_type_entity.dart';
import 'package:finance_app/src/entities/leave_type_entity.dart';
import 'package:finance_app/src/entities/salary_period_entity.dart';
import 'package:finance_app/src/entities/setting_data_entity.dart';
import 'package:finance_app/src/page/hr_payroll/employee/new_employee_page.dart';
import 'package:finance_app/src/provider/hr_payroll/employee/views/particulars_provider.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/widgets/bottom_sheet/add_fixed_deduction_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/add_income_type_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/add_leave_type_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/currency_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/date_time_select_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/list_select_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/shg_contribution_bottom_sheet.dart';
import 'package:flutter/material.dart';

class EmployeeProvider extends BaseProvider {
  EmploymentTypeEntity employmentType;

  TextEditingController employeeIdController = TextEditingController();
  FocusNode employeeIdFocusNode = FocusNode();

  TextEditingController jobTitleController = TextEditingController();
  FocusNode jobTitleFocusNode = FocusNode();

  TextEditingController priceController = TextEditingController();
  FocusNode priceFocusNode = FocusNode();

  TextEditingController foreignLevyController = TextEditingController();
  FocusNode foreignLevyFocusNode = FocusNode();

  List<Map> salaryList = [
    {
      'title': S.current.basic_salary,
      'controller': TextEditingController(),
      'focusNode': FocusNode(),
      'currency': 'SGD',
      'cpfPayable': 1,
    }
  ];

  SalaryPeriodEntity salaryPeriod;

  ContributionEntity selfHelpGroup;

  DateTime hiredDate;

  DateTime confirmationDate;

  String currentSelectEmployeeType = S.current.employee;

  List<EmployeeContactLeaveData> leaveList = [];

  List<EmployeeContactDeductionData> deductionList = [];

  num shgAmount;

  bool get isHideContribution {
    final passType = getParentProvider<NewEmployeeProvider>()
        ?.getChildProvider<ParticularsProvider>()
        ?.passType;
    return passType?.key == 'sp' || passType?.key == 'wp';
  }

  num workingDaysCount = 5;
  List<WorkingDayData> workingDays = [];

  @override
  void dispose() {
    super.dispose();
    employeeIdController.dispose();
    employeeIdFocusNode.dispose();
    jobTitleController.dispose();
    jobTitleFocusNode.dispose();
    priceController.dispose();
    foreignLevyController.dispose();
    priceFocusNode.dispose();
  }

  void unFocus() {
    obtainContext?.call((context) {
      FocusScope.of(context).requestFocus(FocusNode());
    });
  }

  @override
  Future get dataFuture => null;

  void onChangeEmploymentType() {
    unFocus();
    obtainContext?.call((context) async {
      employmentType =
          await showEmploymentTypeSelectBottomSheet(context, employmentType);
      if (employmentType?.key == 'full_time' && salaryPeriod == null) {
        salaryPeriod = Config.settingData.salaryPeriod.firstWhere(
            (element) => element.key == 'monthly',
            orElse: () => null);
      }
      update();
    });
  }

  void onChangeSalaryPeriod() {
    unFocus();
    obtainContext?.call((context) async {
      salaryPeriod =
          await showSalaryPeriodSelectBottomSheet(context, salaryPeriod);
      update();
    });
  }

  void onChangeWorkingDays() {
    unFocus();
    obtainContext?.call((context) async {
      final result = await Routes.navigateTo(
          RouterGenProviders.selectWorkingDayPage,
          params: {
            'workingDaysCount': workingDaysCount,
            'workingDays': workingDays,
          });
      if (result != null) {
        workingDaysCount = result["workingDaysCount"];
        workingDays = result["workingDays"];
      }
      update();
    });
  }

  void onChangeSelfHelpGroup() {
    unFocus();
    obtainContext?.call((context) async {
      final result = await showSHGContributionBottomSheet(context,
          amount: shgAmount, contribution: selfHelpGroup);
      if (result != null) {
        print(result);
        shgAmount = result['amount'];
        selfHelpGroup = result['contribution'];
        update();
      }
    });
  }

  void onAddIncomeType() async {
    unFocus();
    final result =
        await Routes.navigateTo(RouterGenProviders.selectIncomeTypePage);
    if (result != null) {
      salaryList.add(result);
    }
    // obtainContext?.call((context) async {
    //   final result = await showAddIncomeTypeBottomSheet(context, null, null);
    //   if (result != null) {
    //     salaryList.add({
    //       'title': result['incomeType'],
    //       'controller': TextEditingController(text: result['amount']),
    //       'focusNode': FocusNode(),
    //       'currency': salaryList.first['currency'],
    //     });
    //   }
    // });
  }

  void onAddLeaveType() {
    unFocus();
    obtainContext?.call((context) async {
      final result = await showAddLeaveTypeBottomSheet(context, null, null);
      if (result != null) {
        if (leaveList == null) leaveList = [];

        leaveList.add(EmployeeContactLeaveData()
          ..name = (result['leaveType'] as LeaveTypeEntity).key
          ..amount = int.parse(result['amount']));
        update();
      }
    });
  }

  void onChangeLeaveType(EmployeeContactLeaveData e) {
    unFocus();
    obtainContext?.call((context) async {
      final leaveType = Config.settingData.leaveType
          .firstWhere((element) => element.key == e.name, orElse: () => null);
      final result = await showAddLeaveTypeBottomSheet(
        context,
        e.amount?.toString(),
        leaveType,
      );
      if (result != null && result is Map) {
        e.name = (result['leaveType'] as LeaveTypeEntity).key;
        e.amount = int.parse(result['amount']);
        update();
      } else if (result != null && result is bool) {
        leaveList.remove(e);
        update();
      }
    });
  }

  void onAddFixedDeduction() {
    unFocus();
    obtainContext?.call((context) async {
      final result = await showAddDeductionTypeBottomSheet(context, null, null);
      if (result != null) {
        deductionList.add(EmployeeContactDeductionData()
          ..name = result['deductionType']
          ..amount = int.parse(result['amount'])
          ..currencyCode = salaryList.first['currency']);
        update();
      }
    });
  }

  void onChangeHiredDate() {
    unFocus();
    obtainContext?.call((context) async {
      final DateTime dateTime = await showDateTimeSelectBottomSheet(
          context, S.current.hired_date, hiredDate,
          withinFinancialYear: false);
      if (dateTime != null) {
        hiredDate = dateTime;
        update();
      }
    });
  }

  void onChangeConfirmationDate() {
    unFocus();
    obtainContext?.call((context) async {
      final DateTime dateTime = await showDateTimeSelectBottomSheet(
          context, S.current.confirmation_date, confirmationDate,
          withinFinancialYear: false);
      if (dateTime != null) {
        confirmationDate = dateTime;
        update();
      }
    });
  }

  void onChangeAnnualLeave(EmployeeContactLeaveData e, int value) {
    e.amount = value;
  }

  void onChangeUnit(e) {
    unFocus();
    obtainContext?.call((context) async {
      SettingDataCurrency data = Config.settingData.currency.firstWhere(
          (element) => element.key == e['currency'],
          orElse: () => null);
      data = await showCurrencyBottomSheet(context, data);
      e['currency'] = data.key;
      update();
    });
  }

  void onChangeEmployeeType(String e) {
    if (currentSelectEmployeeType == e) return;
    currentSelectEmployeeType = e;
    update();
  }

  void onSelectIncomeType(e) {
    unFocus();
    obtainContext?.call((context) async {
      final result = await showAddIncomeTypeBottomSheet(
          context,
          e['controller'].text,
          e['title'],
          e['wageType'],
          e['cpfPayable'],
          false);
      if (result != null && result is Map) {
        e['title'] = result['incomeType'];
        e['controller'].text = result['amount'];
      } else if (result != null && result is bool) {
        salaryList.remove(e);
        Timer(Duration(milliseconds: 800), () {
          (e['controller'] as TextEditingController).dispose();
          (e['focusNode'] as FocusNode).dispose();
        });
      }
      update();
    });
  }

  void onSelectFixedDeduction(EmployeeContactDeductionData e) {
    unFocus();
    obtainContext?.call((context) async {
      final result = await showAddDeductionTypeBottomSheet(
          context, e.amount?.toString(), e.name);
      if (result != null && result is Map) {
        e.name = result['deductionType'];
        e.amount = int.parse(result['amount']?.toString());
      } else if (result != null && result is bool) {
        deductionList.remove(e);
      }
      update();
    });
  }
}
